#include <cstdio>
#include <cstdlib>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <functional>
#include <memory>
#include <fstream>

#include "Server.hpp"
#include "protocol.hpp"
#include "Comm.hpp"
#include "daemon.hpp"
#include "HttpProtocol.hpp"
#include "Calculate.hpp"
#include "Socket.hpp"

using task_t = std::function<std::string(std::string)>;

std::string SuffixToType(std::string suffix)
{
    if (suffix == ".html" || suffix == ".htm")
        return "text/html";
    else if (suffix == ".jpg")
        return "image/jpeg";
    return "";
}

std::string Function(std::string datagram)
{
    MyHttp::HttpRequest req;   // 请求报文
    MyHttp::HttpResponse resp; // 响应报文

    // 1. 反序列化，形成结构化字段
    req.Deserialize(datagram);
    // 2. 解析，拿到各个字段
    req.Parse();
    req.DebugPrint();
    // 3. 读取requester需要的资源信息
    std::string content;
    // 没有找到资源信息
    if (!req.ReadFile(content))
    {
        // 更新状态码
        resp.SetRespNum("404");
        // 更新状态码描述
        resp.SetRespNumMessage();
        // 读取404页面的网页内容
        req.Get404(content);
    }

    resp.SetRespNum("307");
    resp.SetRespNumMessage();

    // 添加正文
    resp.AddMessage(content);
    // 添加报头：正文长度
    resp.AddContentLength(std::to_string(content.size()));
    // 添加报头：正文传输的类型
    resp.AddContentType(SuffixToType(".html"));
    resp.AddLocation("https://www.qq.com/");

    // 响应报头
    std::string response;
    resp.Serialize(response);
    std::cout << response << std::endl;
    return response;
}

int main(int argc, const char *argv[])
{
    // 判断是否输入了端口号，端口号是表示本机唯一进行本次网络通信的进程
    if (argc != 2)
    {
        printf("Usage:\n\t%s server_port\n\n", argv[0]);
        exit(0);
    }

    // 将server变成守护进程，从此不会被用户的登录和退出所影响
    // Daemon(false, false);

    // 拿端口号
    in_port_t server_port = std::stoi(argv[1]);

    // 初始化server，并交付其内部线程执行的IO方法
    std::unique_ptr<Server<task_t>> server = std::make_unique<Server<task_t>>(server_port,
                                                                              std::bind(Function, std::placeholders::_1));
    // 这里使用占位符，就要求我们再调用该函数的时候，要自己传入参数
    // 主线程进行accept， 线程池中执行Function方法-》IO
    server->Running();

    return 0;
}
